package star.oath.framework.util;

import java.util.*;
import java.util.regex.*;

public class StringUtils {

    /**
     * 获取字符串长度
     * @param input 输入的字符串
     * @return 字符串长度
     */
    public static int length(String input) {
        return input == null ? 0 : input.length();
    }

    /**
     * 判断是否为null或空串
     * @param t 用于判断的参数
     * @return true or false
     */
    public static <T> boolean isEmpty(T t) {
        String string = String.valueOf(t);
        return "".equals(string) || "null".equalsIgnoreCase(string) || "undefined".equals(string);
    }

    /**
     * 判断是否不为null和空串
     * @param t 用于判断的参数
     * @return true or false
     */
    public static <T> boolean isNotEmpty(T t) {
        return !isEmpty(t);
    }

    /**
     * 判断是否为null或空串或空白
     * @param t 用于判断的参数
     * @return true or false
     */
    public static <T> boolean isBlank(T t) {
        String string = String.valueOf(t);
        return "".equals(trim(string))
                || "undefined".equalsIgnoreCase(string)
                || "null".equalsIgnoreCase(string)
                || "None".equalsIgnoreCase(string)
                || "NaN".equalsIgnoreCase(string);
    }

    /**
     * 判断是否不为null和空串和空白
     * @param t 用于判断的参数
     * @return true or false
     */
    public static <T> boolean isNotBlank(T t) {
        return !isBlank(t);
    }

    /**
     * 判断两个字符串内容是否相同
     * @param str1
     * @param str2
     * @return
     */
    public static boolean equals(String str1, String str2) {
        return String.valueOf(str1).equals(String.valueOf(str2));
    }

    /**
     * 判断两个字符串内容是否相同（忽略大小写）
     * @param str1
     * @param str2
     * @return
     */
    public static boolean equalsIgnoreCase(String str1, String str2) {
        return String.valueOf(str1).equalsIgnoreCase(String.valueOf(str2));
    }

    /**
     * 去除字符串首尾的所有空白字符，包括：
     * - 半角空格( )、全角空格(　)
     * - 换行符(\n)、回车符(\r)
     * - 制表符(\t)、垂直制表符(\u000B)、换页符(\f)
     * - 其他Unicode空白字符
     *
     * @param input 待处理的字符串
     * @return 去除首尾空白后的字符串，如果输入为null则返回null
     */
    public static String trim(String input) {
        if (input == null) {
            return null;
        }
        // 使用正则表达式匹配所有空白字符（包括Unicode空白）
        // ^表示字符串开始，\\s+表示一个或多个空白字符
        // \\s+表示一个或多个空白字符，$表示字符串结束
        return input.replaceAll("^[\\s\\u3000]+|[\\s\\u3000]+$", "");
    }

    /**
     * 反转字符串
     * @param input 输入字符串
     * @return 反转后的字符串，输入为null时返回null
     */
    public static String reverse(String input) {
        if (input == null) {
            return null;
        }
        return new StringBuilder(input).reverse().toString();
    }

    /**
     * 将字符串转换为大写
     * @param input
     * @return
     */
    public static String toUpperCase(String input) {
        return input == null ? "" : input.toUpperCase();
    }

    /**
     * 将字符串转换为小写
     * @param input
     * @return
     */
    public static String toLowerCase(String input) {
        return input == null ? "" : input.toLowerCase();
    }

    /**
     * 将下划线命名转换为驼峰命名
     * @param snakeCase 下划线形式的字符串
     * @return 驼峰形式的字符串
     */
    public static String toCamelCase(String snakeCase) {
        if (snakeCase == null || snakeCase.isEmpty()) {
            return snakeCase;
        }
        // 分割字符串并转换为驼峰
        String[] parts = snakeCase.split("_");
        StringBuilder camelCaseBuilder = new StringBuilder(parts[0]);
        for (int i = 1; i < parts.length; i++) {
            if (!parts[i].isEmpty()) {
                camelCaseBuilder.append(Character.toUpperCase(parts[i].charAt(0)));
                camelCaseBuilder.append(parts[i].substring(1).toLowerCase());
            }
        }
        return camelCaseBuilder.toString();
    }

    /**
     * 将驼峰命名转换为下划线命名
     * @param camelCase 驼峰形式的字符串
     * @return 下划线形式的字符串
     */
    public static String toSnakeCase(String camelCase) {
        if (camelCase == null || camelCase.isEmpty()) {
            return camelCase;
        }
        // 改进的正则表达式，处理更多边界情况
        // 1. 小写字母后紧跟大写字母的情况
        // 2. 数字后紧跟大写字母的情况
        // 3. 连续大写字母后紧跟小写字母的情况
        String snakeCase = camelCase.replaceAll("(?<=[a-z0-9])([A-Z])", "_$1");
        // 确保结果全小写
        return snakeCase.toLowerCase();
    }

    /**
     * 获取字符串指定索引处的字符
     * @param input
     * @param index
     * @return
     */
    public static Character charAtIndex(String input, int index) {
        if (index < 0 || index >= input.length()) {
            return null;
        }
        return input.charAt(index);
    }

    /**
     * 获取字符串指定索引处的字符
     * @param input
     * @param sequence
     * @return
     */
    public static Character charAtSequence(String input, int sequence) {
        if (sequence < 0 || sequence >= input.length() - 1) {
            return null;
        }
        return input.charAt(sequence - 1);
    }

    /**
     * 获取字符串指定字符的首个下标
     * @param input
     * @param index
     * @return
     */
    public static int firstIndexOf(String input, String index) {
        return input.indexOf(index);
    }

    /**
     * 获取字符串指定字符的末个下标
     * @param input
     * @param index
     * @return
     */
    public static int lastIndexOf(String input, String index) {
        return input.lastIndexOf(index);
    }

    /**
     * 获取字符串指定字符的首个顺序
     * @param input
     * @param sequence
     * @return
     */
    public static int firstSequenceOf(String input, String sequence) {
        return !input.contains(sequence) ? -1 : input.indexOf(sequence) + 1;
    }

    /**
     * 获取字符串指定字符的末个顺序
     * @param input
     * @param sequence
     * @return
     */
    public static int lastSequenceOf(String input, String sequence) {
        return !input.contains(sequence) ? -1 : input.lastIndexOf(sequence) + 1;
    }

    /**
     * 查找校验字符串在输入字符串中所有出现的起始下标
     * @param input 输入字符串
     * @param checkStr 校验字符串
     * @return 包含所有起始下标的数组，如果没有找到则返回空数组
     */
    public static int[] findAllOccurrenceIndex(String input, String checkStr) {
        if (input == null || checkStr == null || input.isEmpty() || checkStr.isEmpty()) {
            return new int[0];
        }
        List<Integer> indices = new ArrayList<>();
        int index = 0;

        while ((index = input.indexOf(checkStr, index)) != -1) {
            indices.add(index);
            index += checkStr.length();
        }
        // 将List转换为数组
        return indices.stream().mapToInt(Integer::intValue).toArray();
    }

    /**
     * 查找校验字符串在输入字符串中所有出现的起始顺序
     * @param input 输入字符串
     * @param checkStr 校验字符串
     * @return 包含所有起始顺序的数组，如果没有找到则返回空数组
     */
    public static int[] findAllOccurrenceSequence(String input, String checkStr) {
        if (input == null || checkStr == null || input.isEmpty() || checkStr.isEmpty()) {
            return new int[0];
        }
        List<Integer> indices = new ArrayList<>();
        int index = 0;

        while ((index = input.indexOf(checkStr, index)) != -1) {
            indices.add(index+1);
            index += checkStr.length();
        }
        // 将List转换为数组
        return indices.stream().mapToInt(Integer::intValue).toArray();
    }

    /**
     * 按照下标截取字符串
     * @param str
     * @param startIndex 起始字符的下标
     * @param endIndex 截止字符的下标
     * @return
     */
    public static String substringByIndex(String str, int startIndex, int endIndex) {
        if (str == null) {
            return null;
        }
        StringBuilder result = new StringBuilder();
        char[] chars = str.toCharArray();
        for (int i = startIndex; i < chars.length && i <= endIndex; i++) {
            result.append(chars[i]);
        }
        return result.toString();
    }

    /**
     * 按照字符顺序截取字符串
     * @param str
     * @param startSequence 起始的第n个字符
     * @param endSequence 截止的第n个字符
     * @return
     */
    public static String substringBySequence(String str, int startSequence, int endSequence) {
        if (str == null) {
            return null;
        }
        StringBuilder result = new StringBuilder();
        char[] chars = str.toCharArray();
        for (int i = startSequence - 1; i < chars.length && i <= endSequence - 1; i++) {
            result.append(chars[i]);
        }
        return result.toString();
    }

    /**
     * 截取从指定下标开始到字符串末尾的子串
     * @param str 原始字符串
     * @param startIndex 起始下标（包含）
     * @return 截取后的子串，如果原始字符串为null则返回null
     */
    public static String substringByStartIndex(String str, int startIndex) {
        if (str == null) {
            return null;
        }
        StringBuilder result = new StringBuilder();
        char[] chars = str.toCharArray();
        for (int i = startIndex; i < chars.length; i++) {
            result.append(chars[i]);
        }
        return result.toString();
    }

    /**
     * 截取从指定序号开始到字符串末尾的子串
     * @param str 原始字符串
     * @param startSequence 起始的第n个字符（从1开始计数）
     * @return 截取后的子串，如果原始字符串为null则返回null
     */
    public static String substringByStartSequence(String str, int startSequence) {
        if (str == null) {
            return null;
        }
        StringBuilder result = new StringBuilder();
        char[] chars = str.toCharArray();
        for (int i = startSequence - 1; i < chars.length; i++) {
            result.append(chars[i]);
        }
        return result.toString();
    }

    /**
     * 按照起始下标和长度截取字符串
     * @param str
     * @param startIndex 起始字符的下标
     * @param length 截取的长度
     * @return
     */
    public static String substringByIndexAndLength(String str, int startIndex, int length) {
        if (str == null) {
            return null;
        }
        if (startIndex < 1) {
            startIndex = 1;
        }
        if (length < 1) {
            length = 0;
        }
        StringBuilder result = new StringBuilder();
        char[] chars = str.toCharArray();
        for (int i = startIndex; i < chars.length && i < startIndex + length; i++) {
            result.append(chars[i]);
        }
        return result.toString();
    }

    /**
     * 按照起始字符顺序和长度截取字符串
     * @param str
     * @param startSequence 起始的第n个字符
     * @param length 截取的长度
     * @return
     */
    public static String substringBySequenceAndLength(String str, int startSequence, int length) {
        if (str == null) {
            return null;
        }
        if (startSequence < 1) {
            startSequence = 1;
        }
        if (length < 1) {
            length = 0;
        }
        StringBuilder result = new StringBuilder();
        char[] chars = str.toCharArray();
        for (int i = startSequence - 1; i < chars.length && i < startSequence + length - 1; i++) {
            result.append(chars[i]);
        }
        return result.toString();
    }

    /**
     * 获取字符串中指定分隔符第一次出现之前的子字符串
     * @param str 原始字符串
     * @param separator 分隔符
     * @return 分隔符之前的子字符串，如果未找到分隔符则返回原字符串
     */
    public static String substringBeforeSeparator(String str, String separator) {
        if (str == null || str.isEmpty() || separator == null || separator.isEmpty()) {
            return str;
        }
        int pos = str.indexOf(separator);
        if (pos == -1) {
            return str;
        }
        return str.substring(0, pos);
    }

    /**
     * 获取字符串中指定分隔符第一次出现之后的子字符串
     * @param str 原始字符串
     * @param separator 分隔符
     * @return 分隔符之后的子字符串，如果未找到分隔符则返回空字符串
     */
    public static String substringAfterSeparator(String str, String separator) {
        if (str == null || str.isEmpty()) {
            return str;
        }
        if (separator == null || separator.isEmpty()) {
            return "";
        }
        int pos = str.indexOf(separator);
        if (pos == -1 || pos == str.length() - separator.length()) {
            return "";
        }
        return str.substring(pos + separator.length());
    }

    /**
     * 批量替换方法，将源字符串中所有需要替换的内容替换为指定内容
     * @param source 源字符串
     * @param replacement 替换后的内容
     * @param targets 需要被替换的内容（可变参数）
     * @return 替换后的字符串
     */
    public static String replaceAll(String source, String replacement, String... targets) {
        if (source == null || source.isEmpty() || targets == null || targets.length == 0) {
            return source;
        }

        String result = source;
        for (String target : targets) {
            if (target != null && !target.isEmpty()) {
                result = result.replace(target, replacement);
            }
        }
        return result;
    }

    /**
     * 批量替换方法，将源字符串中所有需要替换的内容替换为指定内容（忽略大小写）
     * @param source 源字符串
     * @param replacement 替换后的内容
     * @param targets 需要被替换的内容（可变参数）
     * @return 替换后的字符串
     */
    public static String replaceAllIgnoreCase(String source, String replacement, String... targets) {
        if (source == null || source.isEmpty() || targets == null || targets.length == 0) {
            return source;
        }

        String result = source;
        for (String target : targets) {
            if (target != null && !target.isEmpty()) {
                result = result.replaceAll("(?i)" + escapeRegex(target), replacement);
            }
        }
        return result;
    }

    /**
     * 移除源字符串中的所有指定内容
     * @param source 源字符串
     * @param targets 需要移除的内容（可变参数）
     * @return 移除指定内容后的字符串
     */
    public static String removeAll(String source, String... targets) {
        if (source == null || source.isEmpty() || targets == null || targets.length == 0) {
            return source;
        }

        String result = source;
        for (String target : targets) {
            if (target != null && !target.isEmpty()) {
                result = result.replace(target, "");
            }
        }
        return result;
    }

    /**
     * 移除源字符串中的所有指定内容（忽略大小写）
     * @param source 源字符串
     * @param targets 需要移除的内容（可变参数）
     * @return 移除指定内容后的字符串
     */
    public static String removeAllIgnoreCase(String source, String... targets) {
        if (source == null || source.isEmpty() || targets == null || targets.length == 0) {
            return source;
        }
        String result = source;
        for (String target : targets) {
            if (target != null && !target.isEmpty()) {
                // 使用正则表达式实现忽略大小写的替换
                result = result.replaceAll("(?i)" + escapeRegex(target), "");
            }
        }
        return result;
    }
    //转义正则表达式特殊字符
    private static String escapeRegex(String input) {
        return input.replaceAll("[.*+?^${}()|\\[\\]]", "\\\\$0");
    }

    /**
     * 去除字符串中的所有空白字符（包括全角、半角空格、换行符、制表符等）
     * @param input 待处理的字符串
     * @return 移除所有空白字符后的字符串，如果输入为null则返回null
     */
    public static String removeWhitespace(String input){
        if (input == null) {
            return null;
        }
        // 使用正则表达式匹配所有空白字符，包括ASCII空白和Unicode空白
        return input.replaceAll("\\s+", "");
    }

    /**
     * 去除字符串中的所有空白字符（包括全角空格、换行符、制表符等）
     * 同时处理中文全角空格(U+3000)和其他Unicode空白字符
     * @param input 待处理的字符串
     * @return 移除所有空白字符后的字符串，如果输入为null则返回null
     */
    public static String removeWhitespaceWithUnicode(String input) {
        if (input == null) {
            return null;
        }
        // 匹配所有Unicode空白字符，包括：
        // - ASCII空白字符：[\t\n\x0B\f\r ]
        // - 中文全角空格：\u3000
        // - 其他Unicode空白字符：\p{Zs}
        return input.replaceAll("[\\s\\u3000\\p{Zs}]+", "");
    }

    /**
     * 获取一段长string内,某个特定string片段出现的次数
     * @param targetString 目标长文本字符串
     * @param checkString 需要获取出现次数的字符串
     * @return
     */
    public static int countOccurrences(String targetString, String checkString) {
        int count = 0;
        int index = targetString.indexOf(checkString); // 查找第一次出现的位置
        while (index != -1) {
            count++; // 每找到一次子字符串，计数加一
            index = targetString.indexOf(checkString, index + checkString.length()); // 继续从下一个位置开始查找
        }
        return count;
    }

    /**
     * 将字符串数组用指定的分隔符连接成一个字符串
     * @param splitStr 分隔符
     * @param targets 需要连接的字符串数组
     * @return 连接后的字符串，如果数组为空则返回空字符串
     */
    public static String join(String splitStr, String... targets) {
        if (targets == null || targets.length == 0) {
            return "";
        }

        StringBuilder result = new StringBuilder();
        result.append(targets[0]);

        for (int i = 1; i < targets.length; i++) {
            result.append(splitStr).append(targets[i]);
        }

        return result.toString();
    }

    /**
     * 字符串按指定字符分割
     * @param tarStr
     * @param splitStr
     * @return
     */
    public static String[] split(String tarStr, String splitStr) {
        if (tarStr == null) {
            return new String[]{null};
        }
        if (splitStr == null || splitStr.isEmpty()) {
            return new String[]{tarStr};
        }
        int delimiterLength = splitStr.length();
        int inputLength = tarStr.length();
        if (inputLength == 0) {
            return new String[]{""};
        }
        List<String> list = new ArrayList<>();
        int position = 0;
        int delimiterIndex;
        while ((delimiterIndex = tarStr.indexOf(splitStr, position)) != -1) {
            list.add(tarStr.substring(position, delimiterIndex));
            position = delimiterIndex + delimiterLength;
        }
        // 添加最后一部分
        list.add(tarStr.substring(position));
        return list.toArray(new String[0]);
    }

    /**
     * 判断字符串是否以给定字符串开头
     * @param tarStr
     * @param prefix
     * @return
     */
    public static boolean startsWith(String tarStr, String prefix) {
        boolean result = false;
        if (prefix == null) {
            result = true;
        }
        else if (tarStr != null){
            result = tarStr.startsWith(prefix);
        }
        return result;
    }

    /**
     * 判断字符串是否以给定字符串结尾
     * @param tarStr
     * @param suffix
     * @return
     */
    public static boolean endsWith(String tarStr, String suffix) {
        boolean result = false;
        if (suffix == null) {
            result = true;
        }
        else if (tarStr != null){
            result = tarStr.endsWith(suffix);
        }
        return result;
    }

    /**
     * 判断字符串是不是以数字开头
     * @param str
     * @return
     */
    public static boolean startsWithNumber(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(str.charAt(0)+"");
        return isNum.matches();
    }

    /**
     * 判断字符串是不是以数字结尾
     * @param str
     * @return
     */
    public static boolean endsWithNumber(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(str.charAt(str.length()-1)+"");
        return isNum.matches();
    }

    /**
     * 判断字符串中是否包含给定字符
     * @param tarStr
     * @param checkStr
     * @return
     */
    public static boolean contains(String tarStr, String checkStr) {
        boolean result = false;
        if (checkStr == null) {
            result = true;
        }
        else if (tarStr != null){
            result = tarStr.contains(checkStr);
        }
        return result;
    }

    /**
     * 忽略大小写判断字符串中是否包含给定字符
     * @param tarStr
     * @param checkStr
     * @return
     */
    public static boolean containsIgnoreCase(String tarStr, String checkStr) {
        boolean result = false;
        if (checkStr == null) {
            result = true;
        }
        else if (tarStr != null){
            result = tarStr.toLowerCase().contains(checkStr.toLowerCase());
        }
        return result;
    }

    /**
     * 判断字符串中是否包含汉字
     * @param s
     * @return
     */
    public static boolean containsChinese(String s) {
        Pattern pattern = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = pattern.matcher(s);
        if (m.find()) {
            return true;
        }
        return false;
    }

    /**
     * 判断字符串是否包含除了给定字符外的字符
     * @param tarStr 目标字符串
     * @param givenChar 给定字符
     * @return
     */
    public static boolean containsOtherThanGiven(String tarStr ,char givenChar){
        for (int i = 0; i < tarStr.length(); i++) {
            char c = tarStr.charAt(i);
            if (c != givenChar) {
                return true;
            }
        }
        return false;
    }

    /**
     * 左填充字符串至指定长度
     * @param str 原始字符串
     * @param size 目标长度
     * @param padChar 填充字符
     * @return 填充后的字符串
     */
    public static String leftPad(String str, int size, char padChar) {
        if (str == null) {
            return null;
        }
        int pads = size - str.length();
        if (pads <= 0) {
            return str;
        }
        return repeat(padChar, pads).concat(str);
    }

    /**
     * 右填充字符串至指定长度
     * @param str 原始字符串
     * @param size 目标长度
     * @param padChar 填充字符
     * @return 填充后的字符串
     */
    public static String rightPad(String str, int size, char padChar) {
        if (str == null) {
            return null;
        }
        int pads = size - str.length();
        if (pads <= 0) {
            return str;
        }
        return str.concat(repeat(padChar, pads));
    }

    /**
     * 将字符串居中对齐至指定长度
     * @param str 原始字符串
     * @param size 目标长度
     * @return 居中对齐后的字符串
     */
    public static String center(String str, int size) {
        return center(str, size, ' ');
    }

    /**
     * 将字符串居中对齐至指定长度
     * @param str 原始字符串
     * @param size 目标长度
     * @param padChar 填充字符
     * @return 居中对齐后的字符串
     */
    public static String center(String str, int size, char padChar) {
        if (str == null || size <= 0) {
            return str;
        }
        int strLen = str.length();
        int pads = size - strLen;
        if (pads <= 0) {
            return str;
        }

        str = leftPad(str, strLen + pads / 2, padChar);
        str = rightPad(str, size, padChar);
        return str;
    }

    /**
     * 重复字符指定次数
     * @param ch 字符
     * @param repeat 重复次数
     * @return 重复后的字符串
     */
    private static String repeat(char ch, int repeat) {
        char[] buf = new char[repeat];
        for (int i = repeat - 1; i >= 0; i--) {
            buf[i] = ch;
        }
        return new String(buf);
    }

    /**
     * 缩写字符串（超出长度时截断并添加省略号）
     * @param str 原始字符串
     * @param maxWidth 最大宽度（包含省略号）
     * @return 缩写后的字符串
     */
    public static String abbreviate(String str, int maxWidth) {
        final String ELLIPSIS = "...";
        final int ELLIPSIS_LENGTH = ELLIPSIS.length();

        if (str == null) {
            return null;
        }

        if (str.length() <= maxWidth) {
            return str;
        }

        if (maxWidth <= ELLIPSIS_LENGTH) {
            return ELLIPSIS.substring(0, maxWidth);
        }

        return str.substring(0, maxWidth - ELLIPSIS_LENGTH) + ELLIPSIS;
    }

}
